/*   **********************************************************************  **
 **   Copyright notice                                                       **
 **                                                                          **
 **   (c) 2009, Around(J2)ME				                                 **
 **   All rights reserved.                                                   **
 **                                                                          **
 **   This program and the accompanying materials are made available under   **
 **   the terms of the New BSD License which accompanies this    			 **
 **   distribution.											                 **
 **   A copy is found in the textfile LICENSE.txt							 **
 **                                                                          **
 **   This copyright notice MUST APPEAR in all copies of the file!           **
 **                                                                          **
 **   Main developers:                                                       **
 **     Juri Strumpflohner		http://blog.js-development.com	             **
 **		Matthias Braunhofer		http://matthias.jimdo.com                    **
 **                                                                          **
 **  **********************************************************************  */

package com.aroundj2me.xml;

import org.bouncycastle.util.encoders.Hex;

import com.aroundj2me.model.Comment;
import com.aroundj2me.model.Constants;
import com.aroundj2me.model.Encrypter;
import com.aroundj2me.model.Location;
import com.aroundj2me.model.Place;
import com.aroundj2me.utility.StringReplacer;
/**
 * Class responsible for encoding requests into an XML string
 * which is then sent to the server
 *
 */
public class XMLEncoder {
	private StringBuffer xmlString = null;
	
	public XMLEncoder(){
	}
	
	/**
	 * Creates XML header
	 * @param type type of the request (see {@link Constants}
	 */
	private void createXMLHeader(String type) {
		xmlString.append("<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>");
		xmlString.append("<root>");
		xmlString.append("<type>");
		xmlString.append(type);
		xmlString.append("</type>");
	}
	
	/**
	 * creates the piece of the XML required for the validation of the user
	 * on the server-side
	 * @param username name of the user (login-name)
	 * @param password password of the user
	 */
	private void createXMLValidationData(String username, String password){
		xmlString.append("<validationData>");
		xmlString.append("<user>" + username + "</user>");
		xmlString.append("<password>" + new String(Hex.encode(new Encrypter().encryptPassword(password))) + "</password>");
		xmlString.append("</validationData>");
		xmlString.append("<requestBody>");
	}
	
	/**
	 * Creates the end of the XML file
	 */
	private void createXMLEnd(){
		xmlString.append("</requestBody>");
		xmlString.append("</root>");
	}
	
	/**
	 * Encodes a place into XML
	 * @param place {@link Place} object
	 * @param username login-name of the user
	 * @param password password of the user
	 * @return String representing the XML structure
	 */
	public String encodePlaceToXML(Place place, String username, String password){
		xmlString = new StringBuffer();
		createXMLHeader(Constants.COMMIT_PLACE);
		createXMLValidationData(username, password);
		encodePlace(place);
	
		createXMLEnd();
		return xmlString.toString();
	}
	
	//TODO pay attention to special symbols such as < >, & etc... they could damage XML string
	private void encodePlace(Place place) {
		xmlString.append("<place>");
		xmlString.append("<id>" + place.getId() + "</id>");
		xmlString.append("<name>" + replaceCriticalSymbols(place.getName())  + "</name>");
		xmlString.append("<address>" + replaceCriticalSymbols(place.getAddress())  + "</address>");
		xmlString.append("<city>" + replaceCriticalSymbols(place.getCity()) + "</city>");
		xmlString.append("<phone>" + place.getPhone() + "</phone>");
		if(place.getCreationDate()!=null)
			xmlString.append("<creationDate>" + place.getCreationDate() + "</creationDate>");
		xmlString.append("<user>" + place.getUser() + "</user>");
		if(place.getLocation() != null){
			xmlString.append("<location>");
			xmlString.append("<cellid>" + place.getLocation().getCellid() + "</cellid>");
			xmlString.append("<lat>" + place.getLocation().getLat() + "</lat>");
			xmlString.append("<lon>" + place.getLocation().getLon() + "</lon>");
			xmlString.append("</location>");
		}
		xmlString.append("</place>");
	}
	
	/**
	 * Encodes a comment into XML
	 * @param comment {@link Comment} object
	 * @param username login-name of the user
	 * @param password password of the user
	 * @return String representing the XML structure
	 */
	public String encodeCommentToXML(Comment comment, String username, String password){
		xmlString = new StringBuffer();
		createXMLHeader(Constants.COMMIT_PLACE_COMMENT);
		createXMLValidationData(username, password);
		
		xmlString.append("<comment>");
		xmlString.append("<placeid>" + comment.getPlaceId() + "</placeid>");
		xmlString.append("<content>" + comment.getContent() + "</content>");
		xmlString.append("</comment>");
		
		createXMLEnd();
		return xmlString.toString();
	}
	
	/**
	 * encodes a server-request into XML
	 * @param requestParam type of the request (see {@link Constants}
	 * @param databegin start of the data
	 * @param dataAmount amount of the data to be retrieved
	 * @param username login-name of the user
	 * @param password password of the user
	 * @return String representing the XML structure
	 */
	public String encodeRequest(String requestParam, int databegin, int dataAmount, String username, String password){
		xmlString = new StringBuffer();
		createXMLHeader(Constants.RETRIEVE_PLACE);
		createXMLValidationData(username, password);
		xmlString.append("<requestParam>");
			xmlString.append(requestParam);
		xmlString.append("</requestParam>");
		xmlString.append("<beginData>" + databegin + "</beginData>");
		xmlString.append("<dataAmount>" + dataAmount + "</dataAmount>");
		
		
		createXMLEnd();
		return xmlString.toString();
	}
	
	/**
	 * encodes a server-request into XML related for retrieving Location-based
	 * data
	 * @param requestParam type of the request (see {@link Constants}
	 * @param databegin start of the data
	 * @param dataAmount amount of the data to be retrieved
	 * @param categoryName TODO
	 * @param location cell-id for identifying the location on the server-side
	 * @param username login-name of the user
	 * @param password password of the user
	 * @return String representing the XML structure
	 */
	public String encodeRequest(String requestParam, int databegin, int dataAmount, String categoryName, Location location, String username, String password){
		xmlString = new StringBuffer();
		createXMLHeader(Constants.RETRIEVE_PLACE);
		createXMLValidationData(username, password);
		xmlString.append("<requestParam>");
			xmlString.append(requestParam);
		xmlString.append("</requestParam>");
		xmlString.append("<beginData>" + databegin + "</beginData>");
		xmlString.append("<dataAmount>" + dataAmount + "</dataAmount>");
		if(categoryName != null && !categoryName.equals("")){
			xmlString.append("<category>" + categoryName + "</category>");
		}
		
		xmlString.append("<location>");
		xmlString.append("<cellid>" + location.getCellid() + "</cellid>");
		xmlString.append("<lat>" + location.getLat() + "</lat>");
		xmlString.append("<lon>" + location.getLon() + "</lon>");
		xmlString.append("</location>");
		
		createXMLEnd();
		return xmlString.toString();
	}
	
	/**
	 * encodes a XML search request
	 * @param requestParam type of the request (see {@link Constants}
	 * @param searchQuery String representing the search-query
	 * @param username login-name of the user
	 * @param password password of the user
	 * @return String representing the XML structure
	 */
	public String encodeSearchRequest(String requestParam, int databegin, int dataAmount, String searchQuery, Location location, String username, String password){
		xmlString = new StringBuffer();
		createXMLHeader(Constants.RETRIEVE_PLACE);
		createXMLValidationData(username, password);
		
		xmlString.append("<requestParam>");
			xmlString.append(requestParam);
		xmlString.append("</requestParam>");
		xmlString.append("<location>");
		xmlString.append("<cellid>" + location.getCellid() + "</cellid>");
		xmlString.append("<lat>" + location.getLat() + "</lat>");
		xmlString.append("<lon>" + location.getLon() + "</lon>");
		xmlString.append("</location>");
		xmlString.append("<beginData>" + databegin + "</beginData>");
		xmlString.append("<dataAmount>" + dataAmount + "</dataAmount>");
		xmlString.append("<searchQuery>");
		xmlString.append(searchQuery);
		xmlString.append("</searchQuery>");
		
		createXMLEnd();
		return xmlString.toString();
	}
	
	/**
	 * encodes a XML delete request
	 * @param p {@link Place} object to be deleted
	 * @param user login-name of the user
	 * @param password password of the user
	 * @return String representing the XML structure
	 */
	public String encodeDeleteRequest(Place p, String user, String password){
		xmlString = new StringBuffer();
		createXMLHeader(Constants.DELETE_PLACE);
		createXMLValidationData(user, password);
		encodePlace(p);
		
		createXMLEnd();
		return xmlString.toString();
	}
	
	/**
	 * Replaces critical characters which could eventually break the XML document such as
	 * "<" and ">".
	 * @param text String in which critical chars have to be replaced
	 * @return String with replaced chars
	 */
	private String replaceCriticalSymbols(String text){
		if(text == null)
			return null;
		
		StringReplacer replacer = new StringReplacer();
		text = replacer.replace(text, "&", "&amp;");
		text = replacer.replace(text, "<", "&lt;");
		text = replacer.replace(text, ">", "&gt;");
		return text;
	}
}
